﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using VMS.FTS.APPPUSH;
using VMS.FTS.APPPUSH.Plugins;

namespace TestApp
{
    class Program
    {
        static VMSCoreServices core = VMSCoreServices.Instance;

        #region | COMMAND List |
        static Dictionary<string, Tuple<string, string>> commandList = 
            new Dictionary<string, Tuple<string, string>>{
                // command - callback function - descriptions
                { "addimg",new Tuple<string,string>(
                    "InsertBinaryImage",
                    "\n\tAdd binary image data to device\n" +
                    "\t\tUsage: addimg <devID> <imgID> <filepath>"
                    )
                },
                { "updateimg",new Tuple<string,string>(
                    "UpdateBinaryImage",
                    "\n\tUpdate binary image data to device\n" +
                    "\t\tUsage: updateimg <devID> <imgID> <filepath>"
                    )
                },
                { "delimg",new Tuple<string,string>(
                    "DeleteBinaryImage",
                    "\n\tDelete image of device\n" +
                    "\t\tUsage: delimg <devID> <imgID>"
                    )
                },
                { "delallimg",new Tuple<string,string>(
                    "DeleteBinaryImage",
                    "\n\tDelete all images of device\n" +
                    "\t\tUsage: delallimg <devID>"
                    )
                },
                { "listimg",new Tuple<string,string>(
                    "GetListImageIndex",
                    "\n\tList all images of device\n" +
                    "\t\tUsage: listimg <devID>"
                    )
                },
                { "createpage",new Tuple<string,string>(
                    "CreatePageFromFile",
                    "\n\tCreate new page and add to device\n" +
                    "\t\tUsage: createpage <devID> <path>"
                    )
                },
                { "updatepage",new Tuple<string,string>(
                    "UpdatePage",
                    "\n\tUpdate existing page from device\n" +
                    "\t\tUsage: updatepage <devID> <pageID> <path>"
                    )
                },
                { "delpage",new Tuple<string,string>(
                    "DeletePage",
                    "\n\tDelete existing page from device\n" +
                    "\t\tUsage: delpage <devID> <pageID>"
                    )
                },
                { "pageinfo",new Tuple<string,string>(
                    "GetPageInfo",
                    "\n\tGet page infomations device\n" +
                    "\t\tUsage: pageinfo <devID> <pageID>"
                    )
                },
                { "activepage",new Tuple<string,string>(
                    "ActivePage",
                    "\n\tActive or get active page of device\n" +
                    "\t\tUsage: activePage <devID> <pageID> to active one page \n" +
                    "\t\tUsage: activePage ? to get current active page ID"
                    )
                },
                { "inspopup",new Tuple<string,string>(
                    "InsertPopup",
                    "\n\tInsert popup to device\n" +
                    "\t\tUsage: inspopup <devID> <pageID> <popupID> <path>"
                    )
                },
                { "updatepopup",new Tuple<string,string>(
                    "UpdatePopup",
                    "\n\tUpdate popup to device\n" +
                    "\t\tUsage: updatepopup <devID> <pageID> <popupID> <path>"
                    )
                },
                { "delpopup",new Tuple<string,string>(
                    "DeletePopup",
                    "\n\tDelete popup to device\n" +
                    "\t\tUsage: delpopup <devID> <pageID> <popupID>"
                    )
                },
                { "reboot",new Tuple<string,string>(
                    "Reboot",
                    "\n\tReboot device\n" +
                    "\t\tUsage: reboot <devID>"
                    )
                },
                { "check",new Tuple<string,string>(
                    "CheckLed",
                    "\n\tRun check led on device \n" +
                    "\t\tUsage: check <devID>"
                    )
                },
                { "clear",new Tuple<string,string>(
                    "ClearScreen",
                    "\n\tClear device screen \n" +
                    "\t\tUsage: clear <devID>"
                    )
                },
                { "scan",new Tuple<string,string>(
                    "ScanLed",
                    "\n\tScan device screen \n" +
                    "\t\tUsage: scan <devID>"
                    )
                },
                { "capture",new Tuple<string,string>(
                    "CaptureScreen",
                    "\n\tCapture device screen \n" +
                    "\t\tUsage: capture <devID>"
                    )
                },
                { "devices",new Tuple<string,string>(
                    "",
                    "\n\tList all devices\n" +
                    "\t\tUsage: devices"
                    )
                },
                { "devinfo",new Tuple<string,string>(
                    "",
                    "\n\tPrint device info\n" +
                    "\t\tUsage: devinfo <devID>"
                    )
                },
                { "updatefirmware",new Tuple<string,string>(
                    "UpdateFirmware",
                    "\n\tUpdate firmware device\n" +
                    "\t\tUsage: updatefirmware <devID> <firmware path>"
                    )
                },
                { "firmwareinfo",new Tuple<string,string>(
                    "GetVersion",
                    "\n\tGet firmware version of device\n" +
                    "\t\tUsage: firmwareinfo <devID>"
                    )
                },
                { "updatefont",new Tuple<string,string>(
                    "UpdateFont",
                    "\n\tUpdate font to device\n" +
                    "\t\tUsage: updatefont <devID> <font path>"
                    )
                },
                { "dumplayout",new Tuple<string,string>(
                    "DumpLayout",
                    "\n\tDump xml page data to hex\n" +
                    "\t\tUsage: dumplayout <devID> <xml path>"
                    )
                },
                { "dumpfont",new Tuple<string,string>(
                    "",
                    "\n\tDump font data\n" +
                    "\t\tUsage: dumpfont <fontSize = 7, 10 or 12> <options>\n" +
                    "\t\t\tOptions: -bitmap: output to bitmap file at ./Bitmaps/*.bmp\n" +
                    "\t\t\t         default: output to binary file at ./*.font"
                    )
                },
                { "cls",new Tuple<string,string>(
                    "",
                    "\n\tClear screen\n" +
                    "\t\tUsage: cls <devID>"
                    )
                },
            };
        #endregion

        #region | Main function |
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                string helpMessage = "Command list:\n";
                foreach (Tuple<string, string> item in commandList.Values)
                {
                    helpMessage += item.Item2 + "\n";
                }
                string command = "";
                string line = "";

                while (command != "quit")
                {
                    line = Console.ReadLine();
                    string[] tokens = line.Split(' ');
                    command = tokens[0];
                    if (commandList.ContainsKey(command))
                    {
                        processCommand(tokens);
                    }
                    else
                    {
                        if (command == "?")
                        {
                            Console.Clear();
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine(helpMessage);
                            Console.ForegroundColor = ConsoleColor.White;
                        }
                        else if (command != "")
                            Console.WriteLine("Command " + command + " not found! Enter \" ? \" for list command.");

                    }
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("Command > ");
                }
            }
            else if (args.Length == 2 && args[0].Equals("-s") && Path.GetExtension(args[1]).Equals(".vs"))
            {
                int counter = 0;
                string line;
                
                // Read the file and display it line by line.
                System.IO.StreamReader file =
                   new System.IO.StreamReader(args[1]);
                string command;
                bool isFirstLine = true;
                try
                {
                    while ((line = file.ReadLine()) != null)
                    {
                        
                        string[] tokens = line.Split(' ');
                        command = tokens[0];

                        // first command is wait for device to connected
                        if (isFirstLine)
                        {
                            int delay = 0;
                            if (command == "connect")
                            {
                                string devID = tokens[1];
                                delay = int.Parse(tokens[2]);
                                DateTime timeStamp = DateTime.Now;
                                while (true)
                                {
                                    if (delay <= 0)
                                    {
                                        Console.WriteLine("Device connect timeout!");
                                        file.Close();
                                        core.Dispose();
                                        // Suspend the screen.
                                        Console.ReadLine();
                                        return; ;
                                    }

                                    if (core.getDevice(devID).Status.Connected == true)
                                        break;
                                    delay--;
                                    Thread.Sleep(1000);
                                }
                                isFirstLine = false;
                            }
                            else
                            {
                                Console.Write("We MUST wait for device to connected! add command: \"connect <devID> <timeout>\"");
                                file.Close();
                                core.Dispose();
                                // Suspend the screen.
                                Console.ReadLine();
                                return ;
                            }
                        }
                        

                        Console.Write(">>" + counter + "<< Process command: " + command);
                        if (commandList.ContainsKey(command))
                        {
                            processCommand(tokens);
                            Console.WriteLine("--> OK");
                            counter++;
                        }
                        else if (command == "sleep")
                        {
                            int delay = int.Parse(tokens[1]);
                            Console.WriteLine(" " + delay);
                            Thread.Sleep(delay * 1000);
                        }
                        else if (command == "connect")
                            continue;
                        else
                        {
                            Console.WriteLine("--> command not found!");
                            break;
                        }
                        
                    }
                }
                catch (Exception e)
                {

                }
                file.Close();

                // Suspend the screen.
                Console.ReadLine();
            }
            core.Dispose();
        }
        #endregion

        private static void processCommand(string[] tokens)
        {
            string command = tokens[0];
            switch (command.ToLower())
            {
                case "addimg":
                    DoAddImage(tokens);
                    break;
                case "updateimg":
                    Console.WriteLine("Command " + command + " not supported by API!");
                    //DoUpdateImage(tokens);
                    break;
                case "delimg":
                    DoDeleteImage(tokens);
                    break;
                case "delallimg":
                    DoDeleteAllImage(tokens);
                    break;
                case "listimg":
                    DoGetListImageIndex(tokens);
                    break;
                case "createpage":
                    DoCreatePage(tokens);
                    break;
                case "updatepage":
                    //Console.WriteLine("Command " + command + " not supported by API!");
                    DoUpdatePage(tokens);
                    break;
                case "delpage":
                    DoDeletePage(tokens);
                    break;
                case "pageinfo":
                    DoGetPageInfo(tokens);
                    break;
                case "activepage":
                    DoActivePage(tokens);
                    break;
                case "inspopup":
                    DoInsertPopup(tokens);
                    break;
                case "updatepopup":
                    DoUpdatePopup(tokens);
                    break;
                case "delpopup":
                    DoDeletePopup(tokens);
                    break;
                case "reboot":
                case "check":
                case "clear":
                case "scan":
                case "capture":
                case "firmwareinfo":
                    if (tokens.Length == 2)
                    {
                        string devID = tokens[1];
                        InvokeMethodFromDllForDevice(devID, commandList[command].Item1);
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine(commandList[command].Item2);
                        Console.ForegroundColor = ConsoleColor.White;
                    }
                    break;
                case "updatefirmware":
                    DoUpdateFirmware(tokens);
                    break;
                case "devices":
                    core.PrintDevices();
                    break;
                case "devinfo":
                    if (tokens.Length == 2)
                    {
                        string devID = tokens[1];
                        ShowDeviceInfo(devID);
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine(commandList[command].Item2);
                        Console.ForegroundColor = ConsoleColor.White;
                    }

                    break;
                case "dumplayout":
                    DoDumpLayout(tokens);
                    break;
                case "updatefont":
                    DoUpdateFont(tokens);
                    break;
                case "dumpfont":
                    DoDumpFont(tokens);
                    break;
                case "cls":
                    Console.Clear();
                    break;
            }
        }

        private static void DoUpdatePage(string[] tokens)
        {
            throw new NotImplementedException();
        }

        private static void DoUpdateFont(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    string path = tokens[2];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoDumpFont(string[] tokens)
        {
            if (tokens != null && tokens.Length == 2)
            {
                try
                {
                    ushort fontSize = ushort.Parse(tokens[1]);
                    core.FontDump(fontSize);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else if (tokens != null && tokens.Length == 3)
            {
                try
                {
                    ushort fontSize = ushort.Parse(tokens[1]);
                    if (tokens[2].ToLower() == "-bitmap")
                        core.FontDump(fontSize, true);
                    else
                    {
                        Console.WriteLine("\t Unknow option: " + tokens[2] + "! Ignore and use default option");
                        core.FontDump(fontSize);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoDumpLayout(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    string path = tokens[2];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoUpdateFirmware(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    string path = tokens[2];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoDeletePopup(string[] tokens)
        {
            if (tokens != null && tokens.Length == 4)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);
                    ushort popupID = ushort.Parse(tokens[3]);

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID,popupID);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoUpdatePopup(string[] tokens)
        {
            if (tokens != null && tokens.Length == 5)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);
                    ushort popupID = ushort.Parse(tokens[3]);
                    string path = tokens[4];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID,popupID,path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoInsertPopup(string[] tokens)
        {
            if (tokens != null && tokens.Length == 5)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);
                    ushort popupID = ushort.Parse(tokens[3]);
                    string path = tokens[4];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID, popupID, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static object InvokeMethodFromDllForDevice(string devID,string methodName, params object[] @params)
        {
            object dev = core.getDevice(devID);

            Type type = PluginsManager.Instance.GetSupportedDeviceType().Find(d => d.Name.Equals("LETIDevice"));
            // invoke public instance method: public void InsertBinaryImage

            return type.InvokeMember(methodName,
            BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
            null, dev, @params);
        
        }

        #region | Binary Image Controls |
        private static void DoAddImage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 4)
            {
                string devID = tokens[1];
                try
                {
                    ushort imgID = ushort.Parse(tokens[2]);
                    string path = tokens[3];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, imgID, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }
        /*
        private static void DoUpdateImage(string[] tokens)
        {
            if (tokens.Length == 4)
            {
                string devID = tokens[1];
                ushort imgID = ushort.Parse(tokens[2]);
                string path = tokens[3];

                InvokeMethodFromDllForDevice(devID, tokens[0]].Item1, imgID, path);
            } 
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }
        */
        private static void DoDeleteImage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    ushort imgID = ushort.Parse(tokens[2]);

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, imgID);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoDeleteAllImage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 2)
            {
                string devID = tokens[1];

                InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1);
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoGetListImageIndex(string[] tokens)
        {
            if (tokens != null && tokens.Length == 2)
            {
                string command = tokens[0];
                string devID = tokens[1];

                ushort[] temp = (ushort[])InvokeMethodFromDllForDevice(devID, commandList[command].Item1);
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        #endregion

        #region | Page controls |
        private static void DoCreatePage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    string path = tokens[2];

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, path);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoDeletePage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);
                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoGetPageInfo(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);
                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID);
                }
                catch (Exception e)
                {
                    Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoActivePage(string[] tokens)
        {
            if (tokens != null && tokens.Length == 3)
            {
                string devID = tokens[1];
                try
                {
                    ushort pageID = ushort.Parse(tokens[2]);

                    InvokeMethodFromDllForDevice(devID, commandList[tokens[0]].Item1, pageID);
                }
                catch (Exception e)
                {
                    if (tokens[2].Equals("?"))
                        DoGetActivePage(devID);
                    else
                        Console.WriteLine(commandList[tokens[0]].Item2);
                }
            }
            else
            {
                Console.WriteLine(commandList[tokens[0]].Item2);
            }
        }

        private static void DoGetActivePage(string devID)
        {

            InvokeMethodFromDllForDevice(devID, "GetActivePage");
        }
        #endregion

        #region | Others... |
        private static void ShowDeviceInfo(string devID)
        {
            InvokeMethodFromDllForDevice(devID, "ShowDetails");
        }
        #endregion

    }
}
